﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TorchView.GameContent.Data
{
  public sealed class DataBlock
  {
    private List<DataProperty> _Properties;
    private List<DataBlock> _SubBlocks;

    public string Name { get; set; }

    public DataBlock() { }

    public DataBlock(string name)
    {
      Name = name;
    }

    public List<DataProperty> Properties
    {
      get
      {
        if (_Properties == null)
          _Properties = new List<DataProperty>();
        return _Properties;
      }
      set { _Properties = value; }
    }

    public List<DataBlock> SubBlocks
    {
      get
      {
        if (_SubBlocks == null)
          _SubBlocks = new List<DataBlock>();
        return _SubBlocks;
      }
      set { _SubBlocks = value; }
    }

    public T GetPropertyValue<T>(string name, T defaultValue)
    {
      var property = GetProperty(name);
      if (property != null && property.Value is T)
        return (T)property.Value;
      return defaultValue;
    }

    public void SetPropertyValue<T>(string name, T value, PropertyType type = PropertyType.UNKNOWN)
    {
      SetOrClearPropertyValue(true, name, value, type);
    }

    public void SetOrClearPropertyValue<T>(bool setProperty, string name, T value, PropertyType type = PropertyType.UNKNOWN)
    {
      PropertyType actualType = type == PropertyType.UNKNOWN ? GetPropertyType<T>() : type;
      var currentProperty = GetProperty(name);
      if (currentProperty == null)
        Properties.Add(new DataProperty { Name = name, Value = value, Type = actualType });
      else
      {
        currentProperty.Type = actualType;
        currentProperty.Value = value;
      }
    }

    private PropertyType GetPropertyType<T>()
    {
      if (typeof(T) == typeof(int))
        return PropertyType.INTEGER;
      if (typeof(T) == typeof(float))
        return PropertyType.FLOAT;
      if (typeof(T) == typeof(double))
        return PropertyType.DOUBLE;
      if (typeof(T) == typeof(uint))
        return PropertyType.UINTEGER;
      if (typeof(T) == typeof(bool))
        return PropertyType.BOOL;
      if (typeof(T) == typeof(long))
        return PropertyType.INTEGER64;
      return PropertyType.STRING;
    }

    public void RemoveAllProperties(Predicate<DataProperty> predicate)
    {
      if (_Properties != null)
        _Properties.RemoveAll(predicate);
    }

    public DataProperty GetProperty(string name)
    {
      if (_Properties == null)
        return null;
      return _Properties.FirstOrDefault(p => p.Name == name);
    }

    public IEnumerable<DataProperty> GetProperties(string name)
    {
      if (_Properties == null)
        return new DataProperty[0];
      return _Properties.Where(p => p.Name == name);
    }

    public DataBlock GetSubBlock(string name)
    {
      if (_SubBlocks == null)
        return null;
      return _SubBlocks.FirstOrDefault(s => s.Name == name);
    }

    public override string ToString()
    {
      if (Name != null)
        return Name;
      return base.ToString();
    }
  }
}
